package com.free.ext.httpclient.utils;

import com.free.exception.SystemRuntimeException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;


/**
 * <p>
 * 功能概述: 
 * </p>
 * <p>
 * 功能详述: 
 * </p>
 */
public class SSLs
{

    /*========================================================================*
     *                         Public Fields (公共属性)                                                                
     *========================================================================*/
    
    public static SSLTrustManager simpleVerifier = new SSLTrustManager();
    private static SSLSocketFactory sslFactory ;
    private static SSLConnectionSocketFactory sslConnFactory ;
    private static SSLs sslutil = new SSLs();
    private SSLContext sc;
    
    /*========================================================================*
     *                         Private Fields (私有属性)                                                                
     *========================================================================*/

    /*========================================================================*
     *                         Construct Methods (构造方法) 
     *========================================================================*/
    public static SSLs getInstance(){
        return sslutil;
    }
    
    private SSLs(){}
    
    /*========================================================================*
     *                         Public Methods (公有方法)                                                                   
     *========================================================================*/

     public static SSLs custom()
     {
         return new SSLs();
     }
     
     // 信任主机
     public static HostnameVerifier getVerifier() {
         return simpleVerifier;
     }
     
     public synchronized SSLSocketFactory getSSLSF(SSLProtocolVersion sslpv) 
     {
         if (sslFactory != null)
             return sslFactory;
         try {
             SSLContext sc = getSSLContext(sslpv);
             sc.init(null, new TrustManager[] { simpleVerifier }, null);
             sslFactory = sc.getSocketFactory();
         } catch (KeyManagementException e) {
             throw new SystemRuntimeException("SSLs.getSSLSF 发生异常",e);
         }
         return sslFactory;
     }
     
     public synchronized SSLConnectionSocketFactory getSSLCONNSF(SSLProtocolVersion sslpv) 
     {
         if (sslConnFactory != null)
             return sslConnFactory;
         try {
             SSLContext sc = getSSLContext(sslpv);
             sc.init(null, new TrustManager[] { simpleVerifier }, new java.security.SecureRandom());
             sslConnFactory = new SSLConnectionSocketFactory(sc, simpleVerifier);
         } catch (KeyManagementException e) {
             throw new SystemRuntimeException("SSLs.getSSLCONNSF 发生异常",e);
         }
         return sslConnFactory;
     }
     
     public SSLs customSSL(String keyStorePath, String keyStorepass) 
     {
         FileInputStream instream =null;
         KeyStore trustStore = null; 
         try {
             trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
             instream = new FileInputStream(new File(keyStorePath));
             trustStore.load(instream, keyStorepass.toCharArray());
             // 相信自己的CA和所有自签名的证书
             sc= SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build();
         } catch (Exception e) {
             throw new SystemRuntimeException("SSLs.customSSL 发生异常",e);
         } finally{
             try {
                 instream.close();
             } catch (IOException e) {}
         }
         return this;
     }
     
     public SSLContext getSSLContext(SSLProtocolVersion sslpv) 
     {
         try {
             if(sc==null){
                 sc = SSLContext.getInstance(sslpv.getName());
             }
             return sc;
         } catch (NoSuchAlgorithmException e) {
             throw new SystemRuntimeException("SSLs.getSSLContext 发生异常",e);
         }
     }
    
     // 重写X509TrustManager类的三个方法,信任服务器证书
     private static class SSLTrustManager implements  X509TrustManager, HostnameVerifier{
         
         @Override
         public java.security.cert.X509Certificate[] getAcceptedIssuers() {
             return new java.security.cert.X509Certificate[]{};
             //return null;
         }
         
         @Override
         public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
                 String authType) throws CertificateException {
         }
         
         @Override
         public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
                 String authType) throws CertificateException {
         }

         @Override
         public boolean verify(String paramString, SSLSession paramSSLSession) {
             return true;
         }
     };
     
     
     
    
    public enum SSLProtocolVersion
    {
        SSL("SSL"),
        SSLv3("SSLv3"),
        TLSv1("TLSv1"),
        TLSv1_1("TLSv1.1"),
        TLSv1_2("TLSv1.2"),
        ;
        private String name;
        private SSLProtocolVersion(String name){
            this.name = name;
        }
        public String getName(){
            return this.name;
        }
        public static SSLProtocolVersion find(String name){
            for (SSLProtocolVersion pv : SSLProtocolVersion.values()) {
                if(pv.getName().toUpperCase().equals(name.toUpperCase())){
                    return pv;
                }
            }
            throw new RuntimeException("未支持当前ssl版本号："+name);
        }
        
        public  boolean equals(SSLProtocolVersion sslProtocol)
        {
            return this.name.equals(sslProtocol.getName());
        }
    }
    
    /*========================================================================*
     *                         Private Methods (私有方法)                                                                   
     *========================================================================*/
}

